package com.fmatos.carcontrol.bluetooth;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

import com.fmatos.carcontrol.view.CarPreferences;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.ContextWrapper;
import android.os.ParcelUuid;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;

public class BluetoothManager extends ContextWrapper{

	private static final String TAG = BluetoothManager.class.getSimpleName();
	//	private static final Integer REQUEST_ENABLE_BT = 1; // choose any number > 0
	private BluetoothAdapter mBluetoothAdapter;
	private BluetoothSocket socket;
	private ConnectedThread cThread;

//	public static final String PREFERRED_MAC = "00:14:01:17:17:47"; // TODO read from preferences
//	"00:14:01:17:16:55"

	
	public BluetoothManager(Context context) {
		super(context);
	}
	
	public boolean releaseResources() {
		
		Log.d(TAG,"Release resources");
		
		if ( socket != null && socket.isConnected() ) {
			try {
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				socket = null;
			}
		}
		
		return true;
	}
	
	/**
	 * Checks whether device is capable of bluetooth and also if it's enabled
	 * @return
	 */
	public boolean isBluetoothActive() {

		return isCabable() && isEnabled();
	}

	/**
	 * Checks whether device supports bluetooth
	 * @return
	 */
	private boolean isCabable() {
		if ( mBluetoothAdapter == null ) {
			mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
		}
		return mBluetoothAdapter != null;

	}

	/**
	 * Checks whether bluetooth is turned on
	 * @return
	 */
	private boolean isEnabled() {
		//		if ( isCabable() ) {
		//			if (!mBluetoothAdapter.isEnabled()) {
		//				Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
		//				Object a = startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
		//			}
		//		}

		return isCabable();
	}

	public Set<BluetoothDevice> scanPairedDevices() {
		if ( ! isBluetoothActive() ) {
			return null;
		}
		
		Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
		// If there are paired devices
		if (pairedDevices.size() > 0) {
			// Loop through paired devices
			for (BluetoothDevice device : pairedDevices) {
				Set<String> mArrayAdapter = new HashSet<String>();
				// Add the name and address to an array adapter to show in a ListView
				Log.i(TAG,device.getAddress() + " ---> " + device.getName() );
				mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
			}
		}
		
		return pairedDevices;
	}

	public ConnectedThread pair() {
		BluetoothDevice device = pickupDevice();

		socket = openSocket(device);
		
		try {
			if ( socket != null ) {
				socket.connect();
				cThread = new ConnectedThread(socket);
				cThread.start();
				cThread.write("hello arduino");
				return cThread;

			}
		} catch (IOException e) {
			Log.e(TAG,"Could not open socket to " + device.getName());
			try {
				socket.close();
			} catch (IOException e1) {
				e1.printStackTrace();
			}

		}
		
		return null;
	}
	
	public boolean isPaired() {
		return socket != null && socket.isConnected();  
	}
	
	public String getMessage() {
		if ( cThread == null ) {
			return null;
		} else {
			return cThread.getMessage();
		}
	}
	
	public void sendMessage(String message) {
		cThread.write(message);
	}

	private BluetoothSocket openSocket(BluetoothDevice device) {
		
		UUID uuid = null; // UUIDS have to be agreed between server and client in a way that I don't understand
		BluetoothSocket socket = null;
		try {
			ParcelUuid[] uuids = device.getUuids();
			for ( ParcelUuid uuidParcel : uuids) {
				Log.i(TAG,"UUID found = " + uuidParcel.getUuid());
				uuid = uuidParcel.getUuid();
				break;
			}
			
			socket = device.createRfcommSocketToServiceRecord(uuid);
			if ( socket.isConnected() ) {
				socket = null;
			} else {
				Log.i(TAG,"Socket opened");
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return socket;
		
	}

	private BluetoothDevice pickupDevice() {
		Set<BluetoothDevice> pairedDevices = scanPairedDevices();
		String preferredMac = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString(CarPreferences.PREFERRED_MAC, "");
		
		for ( BluetoothDevice device : pairedDevices) {
			
			if ( preferredMac.equals(device.getAddress())) {
				Toast.makeText(getApplicationContext(), "Found preferred MAC address " + preferredMac, Toast.LENGTH_LONG).show();
				Log.i(TAG,"Found preferred MAC address");
				return device;
			}
		}
		
		Toast.makeText(getApplicationContext(), "Could not open socket to preferred MAC address " + preferredMac, Toast.LENGTH_LONG).show();
		return null;
	}
}

/*

! Bluetooth
!! Classes 
!!! BluetoothAdapter
 * Represents the local Bluetooth adapter (Bluetooth radio). 
 * The BluetoothAdapter is the entry-point for all Bluetooth interaction. 
 ** discover other Bluetooth devices
 ** query a list of bonded (paired) devices
 ** instantiate a BluetoothDevice using a known MAC address
 ** and create a BluetoothServerSocket to listen for communications from other devices.
!!! BluetoothDevice
 * Represents a remote Bluetooth device.
 ** request a connection with a remote device through a BluetoothSocket 
 ** or query information about the device such as its name, address, class, and bonding state.
!!! BluetoothSocket
 * similar to tcp socket
 * use InputStream and OutputStream
 ** BluetoothServerSocket listens for open connections
 *** When a remote Bluetooth device makes a connection request to the this device, the BluetoothServerSocket will return a connected BluetoothSocket when the connection is accepted.
 !! Flow
 * Discovery
 ** Caution: Performing device discovery is a heavy procedure for the Bluetooth adapter and will consume a lot of its resources. Once you have found a device to connect, be certain that you always stop discovery with cancelDiscovery() before attempting a connection.
 * Connection 
 ** UUIDS have to be agreed between server and client in a way that I don't understand, before the socket is set up
 */